package com.spring.framework.aop.annotation.advice;

import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * 切面类
 *
 * @author xuweizhi
 */
@Aspect
@Component
@SuppressWarnings("all")
public class AspectAdvice {

	/**
	 * 使用@within时，虽然Child子类没有@Deprecated注解注解，但是其父类具有该注解，因此子类bean调用target1方法可以被匹配，但是这要求子类bean被
	 * 容器管理并且是直接调用具有该注解的父类的方法，子类重写的方法和子类自己的方法都不能被匹配到，即target2和target3方法都不能被匹配到！
	 */
	@Pointcut("@within(Deprecated)")
	public void with1() {
	}

	@Before("with1()")
	public void withBefore() {
		System.out.println("with aop");
	}

	/**
	 * 很明显，使用@target时，子类bean调用父类的方法时不能被匹配到，@target的匹配范围小于@within。
	 */
	@Pointcut("@target(Deprecated)")
	public void target1() {
	}

	@Before("target1()")
	public void targetBefore() {
		System.out.println("target aop");
	}

	/**
	 * 切入点，用于筛选通知将在哪些方法上执行
	 * <p>
	 * 注解 @target通过类型上的某些注解类型来匹配连接点方法，语法为@target(annotation-type)。@within()通过匹配类型上的某些注解类型来
	 * 匹配连接点方法，还会匹配具有该注解的类的子类，语法为@within (annotation-type)。
	 */
	@Pointcut("@within(PointAdvice) || @annotation(PointAdvice)")
	public void pt() {

	}

	/**
	 * 前置通知
	 * 可以通过名称引用定义好的切入点
	 */
	@Before("pt()")
	public void before() {
		System.out.println("---before---");
	}

	/**
	 * 后置通知
	 * 也可以定义自己的切入点
	 */
	@AfterReturning("execution(* AspectAdviceTarget.target())")
	public void afterReturning() {
		System.out.println("---afterReturning---");
	}

	/**
	 * 异常通知
	 */
	@AfterThrowing("pt()")
	public void afterThrowing() {
		System.out.println("---afterThrowing---");
	}

	/**
	 * 最终通知
	 */
	@After("pt()")
	public void after() {
		System.out.println("---after---");
	}

//    /**
//     * 环绕通知
//     *
//     * @param pjp 连接点
//     */
//    @Around("pt()")
//    public Object around(ProceedingJoinPoint pjp) {
//        System.out.println("---around---");
//        try {
//            System.out.println("前置通知");
//            //调用目标方法
//            Object proceed = pjp.proceed();
//            System.out.println("后置通知");
//            return proceed;
//        } catch (Throwable throwable) {
//            System.out.println("异常通知");
//            throwable.printStackTrace();
//            return null;
//        } finally {
//            System.out.println("最终通知");
//        }
//    }
}

